Type CalCoreSubmesh

	Field m_vectorVertex:CalVertex[]
	Field m_vectorTangentsEnabled:Byte[]
	Field m_vectorvectorTangentSpace:CalTangentSpace[][]'CalTangentSpace[]
	Field m_vectorvectorTangentSpacelocal:CalTangentSpace[][]
	Field m_vectorvectorTextureCoordinate:CalTextureCoordinate[][]'CalTextureCoordinate[]
	Field m_vectorPhysicalProperty:CalPhysicalProperty[]
	Field m_vectorFace:CalFace[]
	Field m_vectorSpring:CalSpring[]
	Field m_vectorCoreSubMorphTarget:CalCoreSubMorphTarget[]
	Field m_coreMaterialThreadId:Int
	Field m_lodCount:Int
	
	Method getCoreMaterialThreadId:Int()
	
		Return m_coreMaterialThreadId
	
	End Method

	Method getFaceCount:Int()
		Return m_vectorFace.Length
	End Method
	
	Method getLodCount:Int()
		Return m_lodCount
	End Method
	
	Method getSpringCount:Int()
		Return m_vectorSpring.length
	End Method
	
	Method getVectorFace:CalFace[]()
		Return m_vectorFace
	End Method
	
	Method getVectorPhysicalProperty:CalPhysicalProperty[]()
		Return m_vectorPhysicalProperty
	End Method
	
	Method getVectorSpring:CalSpring[]()
		Return m_vectorSpring
	End Method

	Method getVectorVectorTangentSpace:CalTangentSpace[][]()
	
		Return m_vectorvectorTangentSpace
	
	End Method
	
	Method getVectorVectorTextureCoordinate:CalTextureCoordinate[][]()
		Return m_vectorvectorTextureCoordinate
	End Method
	
	Method getVectorVertex:CalVertex[]()
		Return m_vectorVertex
	End Method
	
	Method getVertexCount:Int()
		Return m_vectorVertex.length
	End Method
	
	Method isTangentsEnabled:Byte(mapId:Int)
		
		If mapId < 0 Or mapId >= m_vectorTangentsEnabled.Length Then
			Return False
		EndIf
		
		Return m_vectorTangentsEnabled[mapId]
	End Method
	
	Method enableTangents:Byte(mapId:Int, enabled:Byte)
		If mapId < 0 Or mapId >= m_vectorTangentsEnabled.length Then
			Return False
		EndIf
		
		m_vectorTangentsEnabled[mapId] = enabled
	
		If enabled = False
			m_vectorvectorTangentSpace[mapId] = New CalTangentSpace[0]
			Return True
		EndIf
	
		m_vectorvectorTangentSpace[mapId] = New CalTangentSpace[m_vectorVertex.Length]
	
		For Local tangentId:Int = 0  To m_vectorvectorTangentSpace[mapId].length-1
			m_vectorvectorTangentSpace[mapId][tangentId] = New CalTangentSpace
		Next
	
		For Local faceId:Int = 0  To m_vectorFace.length-1
			UpdateTangentVector(m_vectorFace[faceId].vertexId[0], m_vectorFace[faceId].vertexId[1], m_vectorFace[faceId].vertexId[2], mapId)
			UpdateTangentVector(m_vectorFace[faceId].vertexId[1], m_vectorFace[faceId].vertexId[2], m_vectorFace[faceId].vertexId[0], mapId)
			UpdateTangentVector(m_vectorFace[faceId].vertexId[2], m_vectorFace[faceId].vertexId[0], m_vectorFace[faceId].vertexId[1], mapId)
		Next
	
		For tangentId=0 To m_vectorvectorTangentSpace[mapId].length-1
			m_vectorvectorTangentSpace[mapId][tangentId].tangent.normalize()
		Next
	
		Return True	
		
	
	End Method
	
	
	Method reserve:Byte(vertexCount:Int, textureCoordinateCount:Int, faceCount:Int, springCount:Int)
	
		m_vectorVertex = New CalVertex[vertexCount]
		m_vectorTangentsEnabled = New Byte[textureCoordinateCount]
		m_vectorvectorTangentSpacelocal = m_vectorvectorTangentSpacelocal[..textureCoordinateCount]
		m_vectorvectorTextureCoordinate = m_vectorvectorTextureCoordinate[..textureCoordinateCount]
		m_vectorvectorTangentSpace = m_vectorvectorTangentSpace[..textureCoordinateCount]
	
		For Local textureCoordinateId=0 To textureCoordinateCount-1
			m_vectorvectorTextureCoordinate[textureCoordinateId] = m_vectorvectorTextureCoordinate[textureCoordinateId][..vertexCount]
	
			If m_vectorTangentsEnabled[textureCoordinateId] = True Then 'Does this even ever happen? how?
				m_vectorvectorTangentSpace[textureCoordinateId] = m_vectorvectorTangentSpace[textureCoordinateId][..vertexCount]
			Else
				m_vectorvectorTangentSpace[textureCoordinateId] = m_vectorvectorTangentSpace[textureCoordinateId][..0]
			EndIf
		Next
	
		m_vectorFace = New CalFace[faceCount]
		m_vectorSpring = New CalSpring[springCount]
	
		' reserve the space for the physical properties if we have springs in the core submesh instance
		If springCount > 0 Then
			m_vectorPhysicalProperty = New CalPhysicalProperty[vertexCount]
		EndIf
		Return True	
		
	
	End Method
	
	Method setCoreMaterialThreadId(coreMaterialThreadId:Int)
	
		m_coreMaterialThreadId = coreMaterialThreadId
	
	End Method
	
	Method setFace:Byte(faceId:Int, face:CalFace)
		If faceId < 0 Or faceId >= m_vectorFace.length Then
			Return False
		EndIf
		
		m_vectorFace[faceId] = face
		Return True	
			
	End Method
	
	Method setLodCount(lodCount:Int)
		m_lodCount = lodCount
	End Method
	
	Method setPhysicalProperty:Byte(vertexId:Int, physicalProperty:CalPhysicalProperty)
	
		If vertexId < 0 Or vertexId >= m_vectorPhysicalProperty.length Then
			Return False
		EndIf
		
		m_vectorPhysicalProperty[vertexId] = physicalProperty
		Return True	
	
	End Method
	
	Method setSpring:Byte(springId:Int, spring:CalSpring)
	
		If springId < 0 Or springId >= m_vectorSpring.length Then
			Return False
		EndIf
		
		m_vectorSpring[springId] = spring
		Return True	
	
	End Method
	
	Method setTangentSpace:Byte(vertexId, textureCoordinateId, tangent:CalVector, crossFactor:Float)
	
		If vertexId < 0 Or vertexId >= m_vectorVertex.length Then
			Return False
		EndIf
		
		If textureCoordinateId < 0 Or textureCoordinateId >= m_vectorvectorTextureCoordinate.length Then 
			Return False
		EndIf
		
		If m_vectorTangentsEnabled[textureCoordinateId] = False Then
			Return False
		EndIf
	
		'this.m_vectorvectorTangentSpace[textureCoordinateId][vertexId].tangent = tangent;
		If m_vectorvectorTangentSpace[textureCoordinateId][vertexId].tangent = Null Then
			m_vectorvectorTangentSpace[textureCoordinateId][vertexId].tangent = CalVector.FromVector(tangent)
		Else
			m_vectorvectorTangentSpace[textureCoordinateId][vertexId].tangent.assignvector(tangent)
		EndIf
		m_vectorvectorTangentSpace[textureCoordinateId][vertexId].crossFactor = crossFactor
	
		Return True
	
	
	End Method
	
	
	Method setTextureCoordinate:Byte(vertexId:Int, textureCoordinateId:Int, textureCoordinate:CalTextureCoordinate)
	
		If textureCoordinateId < 0 Or textureCoordinateId >= m_vectorvectorTextureCoordinate.length Then
			Return False
		EndIf
		If vertexId < 0 Or vertexId >= m_vectorvectorTextureCoordinate[textureCoordinateId].length Then
			Return False
		EndIf
	
		m_vectorvectorTextureCoordinate[textureCoordinateId][vertexId] = textureCoordinate
		Return True	
		
	
	End Method

	Method setVertex:Byte(vertexId:Int, vertex:CalVertex)
	
		If vertexId < 0 Or vertexId >= m_vectorVertex.length
			Return False
		EndIf
	
		m_vectorVertex[vertexId] = vertex
		Return True
			
	
	End Method
	

	Method addCoreSubMorphTarget:Int(coreSubMorphTarget:CalCoreSubMorphTarget)
	
		Local subMorphTargetId = m_vectorCoreSubMorphTarget.length
		m_vectorCoreSubMorphTarget = m_vectorCoreSubMorphTarget[..subMorphTargetId+1] '.push(coreSubMorphTarget)
		m_vectorCoreSubMorphTarget[subMorphTargetId] = coreSubMorphTarget
		Return subMorphTargetId	
	
	End Method
	
	
	Method getCoreSubMorphTarget:CalCoreSubMorphTarget(subMorphTargetId:Int)
	
		If subMorphTargetId < 0 Or subMorphTargetId >= m_vectorCoreSubMorphTarget.length Then
			DebugLog "Invalid Submorph ID "+subMorphTargetId
			Return Null
		EndIf
		
		Return m_vectorCoreSubMorphTarget[subMorphTargetId]	
			
	
	End Method
	
	
	Method getCoreSubMorphTargetCount:Int()
	
		Return m_vectorCoreSubMorphTarget.length
	
	End Method
	
	
	Method getVectorCoreSubMorphTarget:CalCoreSubMorphTarget[]()
	
		Return m_vectorCoreSubMorphTarget
	
	End Method
	
	
	Method scale(factor:Float)
	
		For Local vertexId=0 To m_vectorVertex.length-1
			m_vectorVertex[vertexId].position.multScalarLocal(factor)
		Next
	
		If m_vectorSpring.length > 0 Then
			' There is a problem when we resize and that there is
			' a spring system, I was unable to solve this
			' problem, so I disable the spring system
			' if the scale are too big
			If Abs(factor - 1) > 0.1 Then
				m_vectorSpring = New CalSpring[0]
				m_vectorPhysicalProperty = New CalPhysicalProperty[0]
			EndIf
		EndIf	
	
	End Method
	

	Method UpdateTangentVector(v0:Int, v1:Int, v2:Int, mapId:Int)
	
		Local vvtx:CalVertex[] = getVectorVertex()
		Local vtex:CalTextureCoordinate[] = m_vectorvectorTextureCoordinate[mapId]
	
		' Step 1. Compute the approximate tangent vector.
		Local du1:Float = vtex[v1].u - vtex[v0].u
		Local dv1:Float = vtex[v1].v - vtex[v0].v
		Local du2:Float = vtex[v2].u - vtex[v0].u
		Local dv2:Float = vtex[v2].v - vtex[v0].v
	
		Local prod1:Float = (du1*dv2-dv1*du2)
		Local prod2:Float = (du2*dv1-dv2*du1)
		If Abs(prod1) < 0.000001 Or Abs(prod2) < 0.000001 Then
			Return
		EndIf
	
		Local x:Float = dv2 / prod1
		Local y:Float = dv1 / prod2
	
		Local vec1:CalVector = vectorSub(vvtx[v1].position, vvtx[v0].position)
		Local vec2:CalVector = vectorSub(vvtx[v2].position, vvtx[v0].position)
		Local tangent:CalVector = vec1.multScalarLocal(x).addLocal(vec2.multScalarLocal(y))
	
		' Step 2. Orthonormalize the tangent.
		Local component:Float = vectorDot(tangent, vvtx[v0].normal)
		tangent.subLocal(vectorScalarMult(vvtx[v0].normal, component))
		tangent.normalize()
	
		' Step 3: Add the estimated tangent to the overall estimate for the vertex.
		m_vectorvectorTangentSpace[mapId][v0].tangent.addLocal(tangent)	
	
	End Method

End Type
